<?php

namespace app\admin\service;

use app\admin\exception\AdminException;
use app\admin\model\Admin;
use app\admin\model\Role;
use DI\Annotation\Inject;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use support\bootstrap\Container;

/**
 * 用户登录服务类
 * @package app\admin\service
 */
class Auth
{
    /**
     * 会话key
     */
    const SESSION_ADMIN_KEY = 'ADMIN_USERNAME';

    /**
     * @var Menu
     * @Inject
     */
    protected $menuService = null;

    /**
     * 当前登录用户模型
     * @var Admin
     */
    protected $userModel = null;

    /**
     * @var Collection 当前用户可访问规则列表
     */
    protected $menuList = null;

    /**
     * @var Collection 当前用户角色列表
     */
    protected $roleList = null;

    public function __construct()
    {
        // 设置当前类为单例
        $container = Container::instance();
        $container->injectOn($this);
    }

    /**
     * 初始化
     * 必须将已登录果的信息清除掉 否则会导致登录错乱
     */
    public function init()
    {
        $this->clear();
        $this->clearMenuList();
        $adminSession = $this->getLoginSession();
        if (empty($adminSession)) {
            return;
        }
        $adminModel = Admin::query()->where('id', $adminSession['id'])->first();
        if (!$adminModel) {
            return;
        }
        $this->userModel = $adminModel;
    }

    /**
     * 是否有权访问某个路由
     * @param string $rule
     * @return bool
     */
    public function can($rule)
    {
        if (!$this->isLogin()) {
            return false;
        }
        // 超级用户
        if ($this->userModel->id == 1) {
            return true;
        }
        $rule = $this->menuService->getModelQuery()->where('rule', $rule)->where('status', 'normal')->first();
        if (!$rule){
            return false;
        }
        /** @var $rule \app\admin\model\Menu */
        $rolesIds = $rule->roles()->pluck('id');
        if ($rolesIds->intersect($this->getRoleList()->pluck('id'))->isEmpty()) {
            return false;
        }
        return true;
    }

    /**
     * 获取菜单列表
     * @return Collection|\Illuminate\Support\Collection|null
     */
    public function getMenuList()
    {
        if (!empty($this->menuList)) {
            return $this->menuList;
        }
        if ($this->userModel->id == 1) {
            $this->menuList = $this->menuService->getlist();
            return $this->menuList;
        }
        $this->menuList = new Collection();
        foreach ($this->getRoleList() as $role) {
            /**
             * @var $role Role
             */
            $this->menuList = $this->menuList->merge($role->menus);
        }
        return $this->menuList;
    }

    /**
     * @return Collection|null
     */
    public function getRoleList()
    {
        if (!empty($this->roleList)) {
            return $this->roleList;
        }
        $this->roleList = $this->userModel->roles()->with('menus')->get();
        return $this->roleList;
    }

    /**
     * 是否能登录
     * @param Model $row
     * @throws AdminException
     */
    public function canLogin(Model $row)
    {
        if ($row->status != 'normal') {
            throw new AdminException("账号已被禁用", 403);
        }
        $loginfailureMax = 5;
        $loginfailureTime = 60 * 5;
        $sLoginTime = strtotime($row->logintime) + $loginfailureTime - time();
        if ($row->loginfailure >= $loginfailureMax && $sLoginTime > 0) {
            throw new AdminException("已错误登录" . $row->loginfailure . "次，请" . $sLoginTime . '秒后再试', 403);
        }
    }

    /**
     * 检测密码
     * @param $userPassword string 用户的密码
     * @param $inputPassword string 输入的密码
     * @param string $userSalt string 用户的密码盐
     * @return bool
     */
    public static function checkPassword($userPassword, $inputPassword, $userSalt = '')
    {
        return $userPassword != self::getEncryptPassword($inputPassword, $userSalt);
    }

    /**
     * 加密密码
     * @param string $password 密码
     * @param string $salt 密码盐
     * @return string
     */
    public static function getEncryptPassword($password, $salt = '')
    {
        return md5(md5($password) . $salt );
    }

    /**
     * @param $username string 账号
     * @param $password string 密码
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object
     */
    public function login($username, $password)
    {
        $row = Admin::query()->where('username', $username)->first();
        if (!$row) {
            throw new AdminException('未找到用户', 404);
        }

        $this->canLogin($row);

        if ( !$this->checkPassword($row, $password) ) {
            throw new AdminException("密码错误", 403);
        }

        $row->logintime = date("Y-m-d H:i:s");
        $row->loginfailure = 0;
        $row->save();
        $this->setLoginSession($row->id, $row->username, $row->nickname);
        return $row;
    }

    public function logout()
    {
        // 只需要清除session即可
        $this->clearLoginSession();
    }

    public function setLoginSession($id, $username = '', $nickname = '')
    {
        request()->session()->set(self::SESSION_ADMIN_KEY, [
            'id' => $id,
            'username' => $username,
            'nickname' => $nickname
        ]);
    }

    public function clearLoginSession()
    {
        request()->session()->delete(self::SESSION_ADMIN_KEY);
    }

    public function getLoginSession()
    {
        return request()->session()->get(self::SESSION_ADMIN_KEY);
    }

    /**
     * 清除已登录相关属性
     */
    public function clear()
    {
        $this->userModel = null;
    }

    /**
     * 是否登录
     * @return bool
     */
    public function isLogin()
    {
        return $this->userModel !== null;
    }

    /**
     * 为null 表示未登录
     * @return Admin|null
     */
    public function getUserModel()
    {
        return $this->userModel;
    }

    public function clearMenuList()
    {
        $this->menuList = [];
    }
}
